package top.zackyoung.websocket.server

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
import java.io.IOException
import java.util.concurrent.CopyOnWriteArraySet
import java.util.concurrent.atomic.AtomicInteger
import javax.websocket.OnClose
import javax.websocket.OnError
import javax.websocket.OnOpen
import javax.websocket.Session
import javax.websocket.server.PathParam
import javax.websocket.server.ServerEndpoint


/**
 * @author ZackYoung
 * @date 2021/11/18
 * @version 1.0
 */
@ServerEndpoint("/webSocket/{uid}")
@Component
class WebSocketServer {
    companion object {
        var log: Logger = LoggerFactory.getLogger(this.javaClass)

        //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
        var onlineNum: AtomicInteger = AtomicInteger(0)

        //concurrent包的线程安全Set，用来存放每个客户端对应的WebSocketServer对象。
        var sessionPools: CopyOnWriteArraySet<Session> = CopyOnWriteArraySet()
    }

    /**
     * 有客户端连接成功
     */
    @OnOpen
    fun onOpen(session: Session, @PathParam(value = "uid") uid: String) {
        sessionPools.add(session)
        onlineNum.incrementAndGet()
        log.info(uid + "加入webSocket！当前人数为" + onlineNum)
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    fun onClose(session: Session) {
        sessionPools.remove(session)
        val cnt = onlineNum.decrementAndGet()
        log.info("有连接关闭，当前连接数为：{}", cnt)
    }

    /**
     * 发送消息
     */
    @Throws(IOException::class)
    fun sendMessage(session: Session, message: String) {
        if (session != null) {
            synchronized(session) { session.getBasicRemote().sendText(message) }
        }
    }

    /**
     * 群发消息
     */
    @Throws(IOException::class)
    fun broadCastInfo(message: String) {
        for (session in sessionPools) {
            if (session.isOpen) {
                sendMessage(session, message)
            }
        }
    }

    /**
     * 发生错误
     */
    @OnError
    fun onError(session: Session, throwable: Throwable) {
        log.error("发生错误")
        throwable.printStackTrace()
    }
}